package grades

import (
	"bytes"
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"strings"
)

func RegisterHandlers() {
	handler := new(studentHandler)
	http.Handle("/students", handler)
	http.Handle("/students/", handler)
}

type studentHandler struct{}

func (h studentHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	pathSegments := strings.Split(r.URL.Path, "/")
	switch len(pathSegments) {
	case 2:
		h.getAll(w)
	case 3:
		id, err := strconv.Atoi(pathSegments[2])
		if err != nil {
			w.WriteHeader(http.StatusNotFound)
			return
		}
		h.getOne(w, id)
	case 4:
		id, err := strconv.Atoi(pathSegments[2])
		if err != nil {
			w.WriteHeader(http.StatusNotFound)
			return
		}
		h.addGrades(w, r, id)
	default:
		w.WriteHeader(http.StatusNotFound)
	}
}

func (h studentHandler) getAll(w http.ResponseWriter) {
	studentsMutex.Lock()
	defer studentsMutex.Unlock()

	data, err := h.toJson(students)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("students序列化失败: %v", err)
		return
	}

	w.Header().Add("Content-Type", "application/json")
	w.Write(data)
}

func (h studentHandler) toJson(data any) ([]byte, error) {
	var buf bytes.Buffer
	enc := json.NewEncoder(&buf)
	if err := enc.Encode(data); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

func (h studentHandler) getOne(w http.ResponseWriter, id int) {
	studentsMutex.Lock()
	defer studentsMutex.Unlock()

	student, err := students.GetByID(id)
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		log.Println(err)
		return
	}

	data, err := h.toJson(student)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("student序列化失败: %v", err)
		return
	}

	w.Header().Add("Content-Type", "application/json")
	w.Write(data)
}

func (h studentHandler) addGrades(w http.ResponseWriter, r *http.Request, id int) {
	studentsMutex.Lock()
	defer studentsMutex.Unlock()

	student, err := students.GetByID(id)
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		log.Println(err)
		return
	}

	var grade Grade
	dec := json.NewDecoder(r.Body)
	if err := dec.Decode(&grade); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		log.Println(err)
		return
	}

	student.Grades = append(student.Grades, grade)
	w.WriteHeader(http.StatusCreated)
	data, err := h.toJson(student)
	if err != nil {
		log.Printf("student序列化失败: %v", err)
		return
	}

	w.Header().Add("Content-Type", "application/json")
	w.Write(data)
}
